/**
 * HTML5 Enabler
 * 
 * Supports
 * - <input autofocus>
 * - <input placehoder> -- Rob Nyman @ https://github.com/robnyman/robnymanplayground/tree/master/placeholder
 */
;(function($,__t,__e){
	/// <param name="$">Local jQuery reference for performance.</param>
	/// <param name="__t">Placeholder for reused tag names.</param>
	/// <param name="__e">Placeholder for reused DOM elements.</param>
	/// <remarks>See implementation details at http://dev.w3.org/html5/spec/Overview.html.</remarks>
	
	/**
	 * $.fn.h5 and $.h5 are two different references. $.fn.h5 is added to any jQuery collection (i.e. $('...').h5), 
	 * whereas $.h5 provides a way to call the plugin without a selector. The latter is simply a helper when a selector 
	 * is not needed. This same pattern is implemented for all HTML5 fallbacks herein.
	 */

	// initialize
	$.fn.h5 = function(){ return this; };
	$.h5 = function(){
		$.h5autofocus();
		$.h5placeholder();
		return $;
	};
	
	// tags/elements
	__t = {
		// form tags
		f:{ i:'input', t:'textarea' }
	};
	__e = {
		// form elements
		f:{ i:document.createElement(__t.f.i), t:document.createElement(__t.f.t) }
	};

	// <input autofocus> -- HTML5 spec (Jun 17, 2011), 4.10.19.4
	(function(){
		// TODO: Handle case where user starts typing before focus is set -- should not change focus
		
		// initialize fallbacks
		$.fn.h5autofocus = function(){ return this.focus(); };
		$.h5autofocus = function(){ return $; };
		
		// if input and textarea support placeholder, return
		if('autofocus' in __e.f.i){ return; }

		// focus on the last input element
		$.h5autofocus = function(){ function f(){ $(':input[autofocus]:last').focus(); } $(f); f(); return $; };
	})();

	// <input placeholder> -- HTML5 spec (Jun 17, 2011), 4.10.7.2.12 + 4.10.13
	(function(_pw,_d,_p,_dp,_dt,_si,_sl,_$){
		/// <param name="_pw">Placeholder for the <c>password</c> input type.</param>
		/// <param name="_d">Placeholder for the "data-" prefix for data attributes.</param>
		/// <param name="_p">Placeholder for the name of the <c>placeholder</c> attribute.</param>
		/// <param name="_dp">Placeholder for the "data-placeholder" data attribute.</param>
		/// <param name="_dt">Placeholder for the "data-type" data attribute.</param>
		/// <param name="_si">Placeholder for the selector to get input/textarea elements.</param>
		/// <param name="_sl">Placeholder for the selector to filter <paramref name="_si"/> down to only those with a placeholder attribute.</param>
		/// <param name="_$">Placeholder for a function that wraps its input with a jQuery object and only returns it if a non-blank placeholder exists.</param>
	
		// TODO: Consider implementing this as a hidden label/div behind the field instead of setting the value explicitly
		
		_pw = 'password';
		_dp = (_d = 'data-') + (_p = 'placeholder');
		_dt = _d + 'type';
		_si = [];
		_p in __e.f.i || _si.push(__t.f.i);
		_p in __e.f.t || _si.push(__t.f.t);
		_sl = _si.join('['+_p+'],') + '['+_p+']';
		_si = _si.join(',');
		_$ = function(t){ t = $(t).filter(_sl); return t.length > 0 && t.attr(_dp).replace(/(\n|\r)/g, '') == '' ? t.not(t[0]) : t; };

		// initialize fallbacks
		$.fn.h5placeholder = function(){ return this; };
		$.h5placeholder = function(){ $(_si).h5placeholder(); return $; };
		
		// if input and textarea support placeholder, return
		if(_si == ''){ return; }

		// hides the placeholder
		function hide(e,$i){
			/// <param name="e">Event object.</param>
			/// <param name="$i">Placeholder for the input element to add the placeholder text to.</param>

			// ignore shift/tab
			if(!!e && ((e.shiftKey && e.keyCode == 16) || e.keyCode == 9)){ return; }

			// if no fields or non-placeholder value or not .placeholder, return
			$i = _$(this);// TODO: .filter('.'+_p);
			if($i.length == 0 || $i.val() != $i.attr(_dp)){ return; }

			// clear value, remove .placeholder, reset type
			$i.val('').removeClass(_p);  // TODO: Remove .active
			this.type = $i.attr(_dt) || this.type;
		}
		
		// set text input caret at beginning
		function caret(e,$i){
			/// <param name="e">Event object.</param>
			/// <param name="$i">Placeholder for the input element to add the placeholder text to.</param>
			
			$i = _$(this);
			if($i.val() == $i.attr(_dp)){
				if(this.setSelectionRange) this.setSelectionRange(0, 0);
				e.preventDefault();
				e.stopPropagation();
				return false;
			}
		}

		// shows the placeholder
		function show(e,$i,p,dp,v){
			/// <param name="e">Event object.</param>
			/// <param name="$i">Placeholder for the input element to add the placeholder text to.</param>
			/// <param name="p">Placeholder for the input element's @placeholder.</param>
			/// <param name="dp">Placeholder for the input element's @data-placeholder.</param>
			/// <param name="v">Placeholder for the input element's @value.</param>
		
			$i = _$(this);
			p = $i.attr(_p);
			dp = $i.attr(_dp);
			v = $i.val();

			// update @data-placeholder data property
			if(p != dp && dp == v){
				$i.attr(_dp, dp = p);
				$i.val(v = dp);
			}
			
			// if there's already a value, return
			if($i.length == 0 || v != ''){ return; }
			
			// change password fields, apply caret, add .placeholer, set value
			if(this.type == _pw){ this.type = 'text' };
			caret.apply(this, arguments);
			$i.addClass(_p).val(dp);
		}
		
		// core $.h5placeholder() function
		$.fn.h5placeholder = function(h,i){
			/// <summary>Adds support for the <c>input</c> element's <c>placeholder</c> attribute.</summary>
			/// <param name="h">Placeholder for the applicable event handlers.</summary>
			/// <param name="i">Placeholder for the loop iterator.</summary>
			
			this.each(function($t){
				/// <param name="$t">Placeholder for <c>$(this)</c>.</summary>
				
				$t = $(this);
				
				// if event handlers already added, trigger blur/show
				if(!!$t.data('events')){
					h = $t.data('events').blur;
					for(i=0; i<h.length; i++){ if(h[i].handler == show){ return $t.blur(); } }
				}

				// set @data-placeholder data property
				$t.filter(_sl).attr(_dp, $t.attr(_p));
				
				// attach handlers, trigger blur/show
				$t.filter(_si).focus(caret).blur(show).keydown(hide).keyup(show).click(caret).bind('drop', caret).blur();
			});
			return this;
		};
		
		// hide placeholders on form submit
		$(function(){ 
			$('form').submit(function(){ $(_sl).each(hide); });
		});

		// hide placeholders on page unload
		$(window).unload(function(){ $(_sl).each(hide); });

		// set spec/implemented dates
		$.fn.h5placeholder.spec = '2011-06-17';
		$.fn.h5placeholder.implemented = '2011-06-21';
	})();
	
	// execute fallbacks
	$(function(){ $.h5() });
})(jQuery);
